/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frmodule_mng.c                                     */
/*  NOTE      = 模块管理                                           */
/*  DATE      = 2014/10/29                                         */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <dlfcn.h>
#include <sys/prctl.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frstr.h"
#include "frxml_parse.h"
#include "frversion.h"
#include "conntrack.h"
#include "frame_params.h"
#include "fruser_def.h"
#include "frame.h"
#include "module.h"
#include "frmodule_stub.h"
#include "frmodule_mng.h"

/* 协议解析模块加载函数 */
#define APM_MODULE_FUN_LOAD     "module_init"
#define APM_MODULE_FUN_UNLOAD   "module_exit"

/* 协议解析库最小内存大小 (10M) */
#define APM_ANALYZER_LIB_MEMPOOL_MIN    10485100

#define APM_MODULE_TYPE_LUA         1
#define APM_MODULE_TYPE_MODULE      2

//延迟30sec删除
#define APM_DEL_WAIT_TIME           30

//多长时间检查数据1次(sec)
#define APM_MNG_MODULE_CHK_TIME    2

typedef struct __st_chk_module {
    Frlist_header *p_lst_hdr;
    int i_ip_proto;
    int i_is_autocheck;
} Frchk_module_mng;

FR_STATIC pthread_rwlock_t g_rwlock_mng = PTHREAD_RWLOCK_INITIALIZER;
FR_STATIC Frlist_header *g_p_st_hdr_mng_module_use=NULL;//当前使用模块
FR_STATIC Frlist_header *g_p_st_hdr_mng_module_del=NULL;//需要删除的模块
FR_STATIC pthread_t g_thread_id_chk=0;

FR_STATIC Frmodule_mng* __frmodule_get_module(int i_l7_proto);
FR_STATIC int __frmodule_unregister(int i_l7_proto);
FR_STATIC void __frmodule_free_l7_module(L7_module *p_st_l7_module_dst);
FR_STATIC int __frmodule_load_one_module(const char *p_module_file);

typedef int (*FP_CALC_DLSYM)();
typedef int (*FP_CALC_MODULE_INIT)(void *, const char* , L7_module_config *);
/*******************************************************************************
*  FUNC     :  模块卸载
*  ARGS     :  p_module_file   (模块文件名)
            :  p_so_name       (so名)
            :  p_so_handle     (so加载后的句柄)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frmodule_unload(const char *p_module_file, const char *p_so_name, void *p_so_handle)
{
    FP_CALC_DLSYM p_so_fun=NULL;

    if(p_so_handle == NULL)
        return;

    //运行模块初始化函数
    p_so_fun = (FP_CALC_DLSYM) dlsym( p_so_handle, APM_MODULE_FUN_UNLOAD);
    if(p_so_fun == NULL)
    {
        FRLOG_WARN_DETAIL("module_file=[%s] load so=[%s] fun=[%s] fail", p_module_file, p_so_name, APM_MODULE_FUN_UNLOAD);
        return;
    }

    (*p_so_fun)();
    return;
}

/*******************************************************************************
*  FUNC     :  节点内容出力
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_outbuff       (出力内容指针)
            :  ui_buff_size    (出力内容空间)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
void frmodule_mng_list_node_mng_show(Frlist_node* p_st_node, char *p_outbuff, unsigned int ui_buff_size)
{
    Frmodule_mng *p_st_module_mng = NULL;
    L7_module *p_st_l7_module=NULL;
    
    if(p_st_node==NULL || p_st_node->data == NULL || ui_buff_size <= 0 )
        return;

    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_module_mng == NULL)
        return;

    p_st_l7_module = p_st_module_mng->p_st_l7_module;
    if(p_st_l7_module == NULL || p_st_module_mng->i_is_stub == FR_YES)
        return;
    
    snprintf(p_outbuff, ui_buff_size, "\tl7_proto=%d\tmodule_name=%s %s(handle=%p)\tip_proto=%s(%d) stub=%s autocheck=%s [%s] [%s] l7_module=%p\n"
           , p_st_l7_module->i_l7_proto
           , p_st_l7_module->p_module_name , p_st_l7_module->p_version, p_st_l7_module->p_so_handle
           , FR_L4PROTO2STR(p_st_l7_module->us_l4_proto), p_st_l7_module->us_l4_proto
           , FR_YESNO2STR(p_st_module_mng->i_is_stub)
           , FR_YESNO2STR(p_st_module_mng->i_is_autocheck)
           , p_st_l7_module->p_module_filenm
           , p_st_l7_module->p_so_filenm
           , p_st_l7_module
           );
    return;
}


/*******************************************************************************
*  FUNC     :  管理节点内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     : 
*******************************************************************************/
FR_STATIC void __list_node_mng_free(Frlist_node *p_st_node)
{
    Frmodule_mng *p_st_module_mng = NULL;
    
    if(p_st_node==NULL || p_st_node->data == NULL )
        return;

    //获取节点下的管理模块
    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_module_mng->p_st_l7_module)
        FRLOG_INFO_DETAIL("unload %s(%d)[%s]", p_st_module_mng->p_st_l7_module->p_module_name
                , p_st_module_mng->p_st_l7_module->i_l7_proto
                , p_st_module_mng->p_st_l7_module->p_so_filenm);

    __frmodule_free_l7_module(p_st_module_mng->p_st_l7_module);
    frfree(p_st_module_mng);

    return;
}

/*******************************************************************************
*  FUNC     :  按l7协议查找函数
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_compare_data  (比较用数据)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
FR_STATIC int __list_node_mng_find_l7_proto(Frlist_node *p_st_node, const void *p_compare_data)
{
    Frmodule_mng *p_st_module_mng;
    L7_module *p_st_l7_module;
    if(!p_compare_data)
        return 1;
    
    p_st_l7_module = (L7_module *)p_compare_data;
    p_st_module_mng = (Frmodule_mng*)FRLIST_GET_NODE_DATA(p_st_node);
    
    if(p_st_module_mng == NULL || p_st_module_mng->p_st_l7_module == NULL
       || p_st_l7_module == NULL)
        return 1;
    
    if(p_st_module_mng->p_st_l7_module->i_l7_proto == p_st_l7_module->i_l7_proto )
        return 0;
    return 1;
}

/*******************************************************************************
*  FUNC     :  按handle查找函数
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_compare_data  (比较用数据)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
FR_STATIC int __list_node_mng_find_handle(Frlist_node *p_st_node, const void *p_compare_data)
{
    Frmodule_mng *p_st_module_mng;
    if(!p_compare_data)
        return 1;
    
    p_st_module_mng = (Frmodule_mng*)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_module_mng && p_st_module_mng->p_st_l7_module
       && p_st_module_mng->p_st_l7_module->p_so_handle == p_compare_data )
        return 0;
    return 1;
}

/*******************************************************************************
*  FUNC     :  tcp/udp/any 转成u_short
*  ARGS     :  p_l4proto        (tcp/udp/any)
*  RTN      :  0:失败; 其他成功
*  NOTE     :  tcp->IPPROTO_TCP; udp->IPPROTO_UDP; any -> IPPROTO_TCP | IPPROTO_UDP
*******************************************************************************/
FR_STATIC u_short __frmodule_proto2short(const char *p_l4proto)
{
    u_short us_l4_proto = 0;

    if(p_l4proto == NULL || *p_l4proto == '\0')
        return us_l4_proto;

    if(strcasecmp("tcp", p_l4proto) == 0)
        us_l4_proto = IPPROTO_TCP;
    else if(strcasecmp("udp", p_l4proto) == 0)
        us_l4_proto = IPPROTO_UDP;
    else if(strcasecmp("any", p_l4proto) == 0)
        us_l4_proto = IPPROTO_TCP | IPPROTO_UDP;

    return us_l4_proto;
}

/*******************************************************************************
*  FUNC     :  检查模块配置信息
*  ARGS     :  
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
FR_STATIC int __frmodule_chk_l7_module(L7_module_config *p_st_l7_module_cfg)
{
    u_short us_ip_proto=0;

    if(p_st_l7_module_cfg==NULL)
        return FR_FAIL;

    if(p_st_l7_module_cfg->p_l4_proto == NULL || *(p_st_l7_module_cfg->p_l4_proto) == '\0')
        return FR_FAIL;

    us_ip_proto = __frmodule_proto2short(p_st_l7_module_cfg->p_l4_proto);
    if( us_ip_proto == 0 )
        return FR_FAIL;
    
    if(p_st_l7_module_cfg->p_version==NULL)
        return FR_FAIL;
    
    if(p_st_l7_module_cfg->l7_detect==NULL
        || p_st_l7_module_cfg->l7_analysis==NULL
        || p_st_l7_module_cfg->session_destory==NULL )
        return FR_FAIL;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  l7协议模块释放
*  ARGS     :  
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
FR_STATIC void __frmodule_free_l7_module(L7_module *p_st_l7_module)
{
    if(p_st_l7_module == NULL )
        return ;

    if(p_st_l7_module->p_so_handle)
        frdbg("p_so_handle=%p\t[%s]\n", p_st_l7_module->p_so_handle, p_st_l7_module->p_so_filenm);

    if(p_st_l7_module->p_module_filenm)
    {
        frfree(p_st_l7_module->p_module_filenm);
        p_st_l7_module->p_module_filenm = NULL;
    }

    if(p_st_l7_module->p_so_filenm)
    {
        frfree(p_st_l7_module->p_so_filenm);
        p_st_l7_module->p_so_filenm = NULL;
    }

    if(p_st_l7_module->p_module_name)
    {
        frfree(p_st_l7_module->p_module_name);
        p_st_l7_module->p_module_name = NULL;
    }

    if(p_st_l7_module->p_version)
    {
        frfree(p_st_l7_module->p_version);
        p_st_l7_module->p_version = NULL;
    }
    
    if( p_st_l7_module->p_so_handle != NULL)
    {
        __frmodule_unload(p_st_l7_module->p_module_filenm, p_st_l7_module->p_so_filenm, p_st_l7_module->p_so_handle);
        dlclose(p_st_l7_module->p_so_handle);
        p_st_l7_module->p_so_handle = NULL;
    }

    frfree(p_st_l7_module);
    return ;
}

/*******************************************************************************
*  FUNC     :  更改L7_module信息
*  ARGS     :
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  p_version不更新
*******************************************************************************/
FR_STATIC int __frmodule_update_l7_module(L7_module *p_st_l7_module
                                     , const char *p_module_file
                                     , const char *p_so_filenm
                                     , int i_l7_proto
                                     , const char *p_module_name)
{
    if(p_st_l7_module == NULL)
        return FR_FAIL;

    if(p_st_l7_module->p_module_filenm)
        frfree(p_st_l7_module->p_module_filenm);
    if(p_module_file)
        p_st_l7_module->p_module_filenm = frstrdup(p_module_file);
    else
        p_st_l7_module->p_module_filenm = NULL;

    if(p_st_l7_module->p_so_filenm)
        frfree(p_st_l7_module->p_so_filenm);
    if(p_so_filenm)
        p_st_l7_module->p_so_filenm = frstrdup(p_so_filenm);
    else
        p_st_l7_module->p_so_filenm = NULL;

    if(p_st_l7_module->i_l7_proto != i_l7_proto)
        p_st_l7_module->i_l7_proto = i_l7_proto;

    if(p_st_l7_module->p_module_name)
        frfree(p_st_l7_module->p_module_name);
    if(p_module_name)
        p_st_l7_module->p_module_name = frstrdup(p_module_name);
    else
        p_st_l7_module->p_module_name = NULL;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  从删除模块里回复
*  ARGS     :
*  RTN      :  0:模块不存在;1:模块存在;2:模块存在删除链表，并回复
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frmodule_reuse(const char *p_module_filenm
                             , const char *p_so_filenm
                             , int i_l7_proto
                             , const char *p_module_name
                             , void  *p_so_handle)
{
    Frlist_node *p_st_node_del=NULL, *p_st_node_use=NULL;
    Frmodule_mng *p_st_module_mng_use = NULL, *p_st_module_mng_del = NULL;
    L7_module st_l7_module_tmp;

    //不存在该情况
    //p_st_node_use = frlist_find(g_p_st_hdr_mng_module_use, p_so_handle, __list_node_mng_find_handle);
    //if(p_st_node_use)   //已经存在该模块
    //{
    //    p_st_module_mng_use = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node_use);
    //    if(p_st_module_mng_use)
    //    {
    //        __frmodule_update_l7_module(p_st_module_mng_use->p_st_l7_module
    //                ,p_module_filenm, p_so_filenm, i_l7_proto, p_module_name);
    //        p_st_module_mng_use->i_is_autocheck = i_is_autocheck;
    //    }
    //    FRLOG_INFO_DETAIL("[%s] is loaded", p_so_filenm);
    //    return 1;
    //}

    p_st_node_del = frlist_find(g_p_st_hdr_mng_module_del, p_so_handle, __list_node_mng_find_handle);
    p_st_module_mng_del = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node_del);
    if(p_st_node_del == NULL || p_st_module_mng_del == NULL) //不存在该模块
        return 0;

    __frmodule_update_l7_module(p_st_module_mng_del->p_st_l7_module
                              , p_module_filenm, p_so_filenm, i_l7_proto, p_module_name);
    p_st_module_mng_del->i_is_stub = FR_NO;
    p_st_module_mng_del->i_is_autocheck = (i_l7_proto == APM_L7_SYNCMODULE)? FR_NO : FR_YES;

    //程序该协议的Stub是否存在
    memset(&st_l7_module_tmp, '\0', sizeof(L7_module));
    st_l7_module_tmp.i_l7_proto = i_l7_proto;
    p_st_node_use = frlist_find(g_p_st_hdr_mng_module_use, &st_l7_module_tmp, __list_node_mng_find_l7_proto);
    //使用链表里不存在,或者不是stub时，直接加入
    p_st_module_mng_use = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node_use);
    if(p_st_node_use == NULL || p_st_module_mng_use == NULL || p_st_module_mng_use->i_is_stub == FR_NO)
    {
        frlist_node_apart(g_p_st_hdr_mng_module_del, p_st_node_del);
        frlist_push(g_p_st_hdr_mng_module_use, p_st_node_del);
        FRLOG_INFO_DETAIL("recover from module_del[%s] l7_proto=%d", p_so_filenm, i_l7_proto);
        return 2;
    }

    //使用链表里存在stub
    p_st_module_mng_use->i_is_stub = FR_NO;
    p_st_module_mng_use->i_is_autocheck = (i_l7_proto == APM_L7_SYNCMODULE)? FR_NO : FR_YES;
    __frmodule_free_l7_module(p_st_module_mng_use->p_st_l7_module);
    p_st_module_mng_use->p_st_l7_module =p_st_module_mng_del->p_st_l7_module;

    //释放老数据
    frfree(p_st_module_mng_del);
    frlist_node_free(g_p_st_hdr_mng_module_del, p_st_node_del, 1, NULL);
    FRLOG_INFO_DETAIL("recover from module_del[%s] l7_proto=%d", p_so_filenm, i_l7_proto);

    return 2;
}

/*******************************************************************************
*  FUNC     :  检查主版本
*  ARGS     :
*  RTN      :  FR_SUCC:成功;FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frmodule_chk_version(const char *p_so_version, const char *p_frame_version)
{
    char arr_frame_ver[30];

    if(p_so_version == NULL || *p_so_version == '\0'
       || p_frame_version == NULL || p_frame_version == '\0')
        return FR_FAIL;

    snprintf(arr_frame_ver, sizeof(arr_frame_ver), "%s.", p_frame_version);
    if(strncmp(p_so_version, arr_frame_ver, strlen(arr_frame_ver)) != 0)
        return FR_FAIL;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  模块so注册
*  ARGS     :  
*  RTN      :  0:成功;1:失败;2:相同so已经加载
*  NOTE     :  1.第1次加载时，默认该模块可以进行协议判断
*           :  2.更新模块时,加载当前so,卸载老so
*           :    (协议解析部分要注意释放老so使用的内存)
*******************************************************************************/
FR_STATIC int __frmodule_register(const char *p_module_filenm
                                , const char *p_so_filenm
                                , int i_l7_proto
                                , const char *p_module_name
                                , const char *p_params)
{
    void  *p_so_handle=NULL;
    FP_CALC_MODULE_INIT p_so_fun=NULL;
    L7_module_config st_l7_module_cfg;
    Frmodule_mng *p_st_module_mng = NULL;
    L7_module st_l7_module_tmp, *p_st_l7_module_old=NULL;
    Frlist_node *p_st_node=NULL;
    int i_ret_fun=0, i_ret = 1;
    u_short us_l4_proto = 0;

    if(g_p_st_hdr_mng_module_use == NULL || p_so_filenm == NULL)
        return 1;

    pthread_rwlock_wrlock(&g_rwlock_mng);
    //检查是否存在相同的l7_proto
    p_st_module_mng = __frmodule_get_module(i_l7_proto);
    if(p_st_module_mng)
    {
        FRLOG_WARN_DETAIL("same module_file[%s] l7_proto(%d) (so=%s) is loaded. this time load module_file[%s] so[%s]"
                , p_st_module_mng->p_st_l7_module->p_module_filenm, i_l7_proto
                , p_st_module_mng->p_st_l7_module->p_so_filenm
                , p_module_filenm, p_so_filenm);
        pthread_rwlock_unlock(&g_rwlock_mng);
        return 2;
    }
    p_st_module_mng = NULL;
    //加载so
    p_so_handle=dlopen(p_so_filenm, RTLD_LAZY);
    if(p_so_handle == NULL)
    {
        pthread_rwlock_unlock(&g_rwlock_mng);
        FRLOG_WARN_DETAIL("load file=[%s] error=[%s] fail", p_so_filenm, dlerror());
        return 1;
    }

    //确认同一模块(相同so)的重复注册
    i_ret_fun = __frmodule_reuse(p_module_filenm, p_so_filenm, i_l7_proto, p_module_name, p_so_handle);
    if(i_ret_fun == 1 || i_ret_fun == 2)
    {
        pthread_rwlock_unlock(&g_rwlock_mng);
        dlclose(p_so_handle);
        if(i_ret_fun == 2) //从删除模块里回复时，返回0:成功
            return 0;
        else
            return 2;
    }

    frdbg("module_file[%s] so_handle=%p\t[%s]\n", p_module_filenm, p_so_handle, p_so_filenm);

    //运行模块初始化函数
    p_so_fun = (FP_CALC_MODULE_INIT) dlsym( p_so_handle, APM_MODULE_FUN_LOAD);
    if(p_so_fun == NULL)
    {
        pthread_rwlock_unlock(&g_rwlock_mng);
        dlclose(p_so_handle);
        FRLOG_WARN_DETAIL("module_file=[%s] load so=[%s] fun=[%s] fail", p_module_filenm, p_so_filenm, APM_MODULE_FUN_LOAD);
        return 1;
    }
    
    memset(&st_l7_module_cfg, 0x00, sizeof(L7_module_config));
    i_ret_fun = (*p_so_fun)( &g_st_apm_context, p_params, &st_l7_module_cfg);
    if(i_ret_fun == FR_FAIL)
    {
        pthread_rwlock_unlock(&g_rwlock_mng);
        dlclose(p_so_handle);
        FRLOG_WARN_DETAIL("run module_file=[%s] so=[%s] fun=[%s] fail", p_module_filenm, p_so_filenm, APM_MODULE_FUN_LOAD);
        return 1;
    }
    
    //比较主版本号是否一致
    i_ret_fun = __frmodule_chk_version(st_l7_module_cfg.p_version, frversion_frame() );
    if(i_ret_fun == FR_FAIL)
    {
        pthread_rwlock_unlock(&g_rwlock_mng);
        FRLOG_WARN_DETAIL("check version fail, module_file=[%s] so=[%s] module_version=[%s] frame_version=[%s]"
                        , p_module_filenm, p_so_filenm, st_l7_module_cfg.p_version, frversion_frame());
        goto ERROR;
    }

    //检查st_l7_module参数是否正确
    i_ret_fun = __frmodule_chk_l7_module(&st_l7_module_cfg);
    if(i_ret_fun != FR_SUCC)
    {
        pthread_rwlock_unlock(&g_rwlock_mng);
        FRLOG_WARN_DETAIL("check module fail [%s] ", p_so_filenm);
        goto ERROR;
    }
    us_l4_proto = __frmodule_proto2short(st_l7_module_cfg.p_l4_proto);
    
    //检查该so是否存在
    memset(&st_l7_module_tmp, '\0', sizeof(L7_module));
    st_l7_module_tmp.i_l7_proto = st_l7_module_cfg.i_l7_proto;
    p_st_node = frlist_find(g_p_st_hdr_mng_module_use, &st_l7_module_tmp, __list_node_mng_find_l7_proto);
    //模块不存在
    if(p_st_node == NULL)
    {
        L7_module *p_st_l7_module=NULL;
        p_st_l7_module = (L7_module *) frmalloc(sizeof(L7_module));
        p_st_module_mng = (Frmodule_mng *) frmalloc(sizeof(Frmodule_mng));
        if(p_st_module_mng == NULL || p_st_l7_module == NULL)
        {
            pthread_rwlock_unlock(&g_rwlock_mng);
            if(p_st_l7_module) frfree(p_st_l7_module);
            if(p_st_module_mng) frfree(p_st_module_mng);
            FRLOG_ERROR_DETAIL("frmalloc err");
            goto ERROR;
        }
        memset(p_st_l7_module, '\0', sizeof(L7_module));
        memset(p_st_module_mng, '\0', sizeof(Frmodule_mng));
        p_st_node = frlist_node_create(p_st_module_mng);
        if(p_st_node == NULL)
        {
            pthread_rwlock_unlock(&g_rwlock_mng);
            FRLOG_ERROR_DETAIL("frlist_node_create err");
            frfree(p_st_l7_module);
            frfree(p_st_module_mng);
            goto ERROR;
        }

        p_st_l7_module->p_module_filenm = frstrdup(p_module_filenm);
        p_st_l7_module->p_so_filenm = frstrdup(p_so_filenm);
        p_st_l7_module->i_l7_proto = i_l7_proto;
        p_st_l7_module->us_l4_proto = us_l4_proto;
        p_st_l7_module->p_module_name = frstrdup(p_module_name);
        p_st_l7_module->p_version = frstrdup(st_l7_module_cfg.p_version);
        p_st_l7_module->l7_detect = st_l7_module_cfg.l7_detect;
        p_st_l7_module->l7_analysis = st_l7_module_cfg.l7_analysis;
        p_st_l7_module->session_destory = st_l7_module_cfg.session_destory;
        p_st_l7_module->p_so_handle = p_so_handle;
        p_st_l7_module->ul_refcnt = 0L;

        p_st_module_mng->p_st_l7_module = p_st_l7_module;
        p_st_module_mng->i_is_stub = FR_NO;
        p_st_module_mng->i_is_autocheck = (i_l7_proto == APM_L7_SYNCMODULE)? FR_NO : FR_YES;

        frlist_push(g_p_st_hdr_mng_module_use, p_st_node);
        pthread_rwlock_unlock(&g_rwlock_mng);
        //FRLOG_INFO_DETAIL("load %s[%s] params[%s]ok", p_module_name, p_so_name, p_params);

        return 0;
    }
    else
    {
        L7_module *p_st_l7_module=NULL;
        //更新stub模块
        p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
        p_st_l7_module_old = p_st_module_mng->p_st_l7_module;
        p_st_l7_module = (L7_module *) frmalloc(sizeof(L7_module));
        if(p_st_l7_module == NULL)
        {
            pthread_rwlock_unlock(&g_rwlock_mng);
            FRLOG_ERROR_DETAIL("malloc err");
            goto ERROR;
        }

        p_st_l7_module->p_module_filenm = frstrdup(p_module_filenm);
        p_st_l7_module->p_so_filenm = frstrdup(p_so_filenm);
        p_st_l7_module->i_l7_proto = i_l7_proto;
        p_st_l7_module->us_l4_proto = us_l4_proto;
        p_st_l7_module->p_module_name = frstrdup(p_module_name);
        p_st_l7_module->p_version = frstrdup(st_l7_module_cfg.p_version);
        p_st_l7_module->l7_detect = st_l7_module_cfg.l7_detect;
        p_st_l7_module->l7_analysis = st_l7_module_cfg.l7_analysis;
        p_st_l7_module->session_destory = st_l7_module_cfg.session_destory;
        p_st_l7_module->p_so_handle = p_so_handle;
        p_st_l7_module->ul_refcnt = p_st_l7_module_old->ul_refcnt;

        p_st_module_mng->p_st_l7_module = p_st_l7_module;
        p_st_module_mng->i_is_stub = FR_NO;
        p_st_module_mng->i_is_autocheck = (i_l7_proto == APM_L7_SYNCMODULE)? FR_NO : FR_YES;

        pthread_rwlock_unlock(&g_rwlock_mng);
        FRLOG_INFO_DETAIL("load %s[%s] params[%s]ok", p_module_name, p_so_filenm, p_params);

        //释放老模块信息
        __frmodule_free_l7_module(p_st_l7_module_old);

        FRLOG_INFO_DETAIL("load %s[%s] ok", p_module_name, p_so_filenm);
        return 0;
    }

ERROR:
    if(p_so_handle)
    {
        __frmodule_unload(p_module_filenm, p_so_filenm, p_so_handle);
        dlclose(p_so_handle);
    }

    return i_ret;
}


/*******************************************************************************
*  FUNC     :  从配置文件中读取解析库配置
*  ARGS     :  p_module_file        (模块配置文件名 const char*)
*  RTN      :  0:成功;1:失败;2:相同so已经加载
*  NOTE     :
*******************************************************************************/
int frmodule_register_path(const char *p_module_file)
{
    int i_ret_fun=FR_FAIL;

    if(p_module_file == NULL || *p_module_file == '\0')
        return FR_FAIL;

    i_ret_fun = __frmodule_load_one_module(p_module_file);
    FRLOG_INFO_DETAIL("__frmodule_load_one_module [%s] ret=%d", p_module_file, i_ret_fun);

    return i_ret_fun;
}

/*******************************************************************************
*  FUNC     :  卸载指定模块
*  ARGS     :  p_module_file        (模块配置文件名 const char*)
*  RTN      :  0:成功,1:失败,2:不存在,3:xml解析失败
*  NOTE     :
*******************************************************************************/
int frmodule_unregister_path(const char *p_module_file, int i_l7_proto)
{
    int i_ret_fun=0;

    if (p_module_file)
    {
        char *p_l7_proto = NULL;
        //l7协议号
        i_ret_fun = frxml_get2doc_prop_string(p_module_file, "/", APM_CFG_MODULE_KEY_MODULE, APM_CFG_MODULE_KEY_L7_PROTO, &p_l7_proto);
        if(i_ret_fun == FR_FAIL || p_l7_proto == NULL || *p_l7_proto == '\0')
        {
            FRLOG_WARN_DETAIL("load module=[%s] [%s] [%s] fail", p_module_file, APM_CFG_MODULE_KEY_MODULE, APM_CFG_MODULE_KEY_L7_PROTO);
            if(p_l7_proto)
                frfree(p_l7_proto);
            return 3;
        }
        i_l7_proto = atoi(p_l7_proto);
        frfree(p_l7_proto);
        p_l7_proto = NULL;
    }

    pthread_rwlock_wrlock(&g_rwlock_mng);
    i_ret_fun = __frmodule_unregister(i_l7_proto);
    pthread_rwlock_unlock(&g_rwlock_mng);

    FRLOG_INFO_DETAIL("__frmodule_unregister [%s] (l7=%d) ret=%d", p_module_file, i_l7_proto, i_ret_fun);

    return i_ret_fun;
}
/*******************************************************************************
*  FUNC     :  卸载指定模块
*  ARGS     :  i_l7_proto      (全局使用的l7号)
*  RTN      :  0:成功,1:失败,2:不存在
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frmodule_unregister(int i_l7_proto)
{
    Frlist_node *p_st_node=NULL;
    Frmodule_mng *p_st_module_mng = NULL, *p_mng_module_del=NULL;
    L7_module st_l7_module_tmp, *p_st_l7_module=NULL;
    
    if(g_p_st_hdr_mng_module_use == NULL || g_p_st_hdr_mng_module_del==NULL)
        return 1;
    
    memset(&st_l7_module_tmp, '\0', sizeof(L7_module));
    st_l7_module_tmp.i_l7_proto = i_l7_proto;
    
    //查询节点
    p_st_node = frlist_find(g_p_st_hdr_mng_module_use, &st_l7_module_tmp, __list_node_mng_find_l7_proto);
    if(p_st_node == NULL)
    {
        FRLOG_WARN_DETAIL("module not found, l7_proto=%d", i_l7_proto);
        return 2;
    }
    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_module_mng == NULL || p_st_module_mng->i_is_stub == FR_YES )
    {
        FRLOG_INFO_DETAIL("module not exist, l7_proto=%d", i_l7_proto);
        return 2;
    }
    
    //生成删除节点
    p_mng_module_del = (Frmodule_mng *) frmalloc(sizeof(Frmodule_mng));
    p_st_l7_module  = (L7_module *) frmalloc(sizeof(L7_module));
    if(p_mng_module_del == NULL || p_st_l7_module == NULL )
    {
        if(p_mng_module_del)
            frfree(p_mng_module_del);
        if(p_st_l7_module)
            frfree(p_st_l7_module);
        FRLOG_ERROR_DETAIL("frmalloc err");
        return 1;
    }
    memcpy(p_mng_module_del, p_st_module_mng, sizeof(Frmodule_mng));
    memset(p_st_l7_module, 0x00, sizeof(L7_module));
    p_st_module_mng->p_st_l7_module = p_st_l7_module;
    //stub里保留模块名
    if(p_mng_module_del->p_st_l7_module->p_module_name)
        p_st_module_mng->p_st_l7_module->p_module_name = frstrdup(p_mng_module_del->p_st_l7_module->p_module_name);
    //设置老节点为stub
    p_st_module_mng->i_is_stub = FR_YES;
    frl7module_stub(p_st_module_mng->p_st_l7_module);

    p_st_node = frlist_node_create(p_mng_module_del);
    if(p_st_node == NULL)
    {
        //该情况不应该发生，不考虑相关资源的释放
        //if(p_mng_module_del->p_st_l7_module && p_mng_module_del->p_st_l7_module->p_module_name)
        //    frfree(p_mng_module_del->p_st_l7_module->p_module_name);
        //if(p_mng_module_del->p_st_l7_module)
        //    frfree(p_mng_module_del->p_st_l7_module);
        frfree(p_mng_module_del);
        FRLOG_ERROR_DETAIL("frmalloc err");
        return 1;
    }
    p_st_module_mng->p_st_l7_module->l_del_tv_sec = 0;
    frlist_push(g_p_st_hdr_mng_module_del, p_st_node);

    return 0;
}

/*******************************************************************************
*  FUNC     :  节点检查，并删除
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_data          (void *)
*  RTN      :
*  NOTE     : 0:pf_run控制退出; 1:运行到最后
*******************************************************************************/
FR_STATIC int __list_node_mng_chk_del(Frlist_node* p_st_node, const void *p_data)
{
    Frmodule_mng *p_st_module_mng = NULL;
    struct timeval st_timeval_pkg;
    
    if(p_st_node==NULL || p_st_node->data == NULL )
        return 1;

    //获取节点下的管理模块
    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    //frwarn("%s(l7_module=%p) ref=%lu\n", p_st_module_mng->p_st_l7_module->p_module_name, p_st_module_mng->p_st_l7_module, p_st_module_mng->p_st_l7_module->ul_refcnt);
    if(p_st_module_mng->p_st_l7_module->ul_refcnt > 0)
        return 1;

    //延迟30秒后再删除
    gettimeofday (&st_timeval_pkg, NULL);
    if(p_st_module_mng->p_st_l7_module->l_del_tv_sec == 0)
    {
        p_st_module_mng->p_st_l7_module->l_del_tv_sec = st_timeval_pkg.tv_sec;
        return 1;
    }
    else if(st_timeval_pkg.tv_sec - p_st_module_mng->p_st_l7_module->l_del_tv_sec <= APM_DEL_WAIT_TIME)
        return 1;

    //frwarn("%s(l7_module=%p) ref=%lu\n", p_st_module_mng->p_st_l7_module->p_module_name, p_st_module_mng->p_st_l7_module, p_st_module_mng->p_st_l7_module->ul_refcnt);
    frlist_node_free(g_p_st_hdr_mng_module_del, p_st_node, 1, __list_node_mng_free);
    return 1;
}

/*******************************************************************************
*  FUNC     :  按模块名释放
*  ARGS     :  i_l7_proto   (全局使用的l7代号)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
FR_STATIC int __frmodule_del_no_ref(void)
{
    if(g_p_st_hdr_mng_module_del == NULL)
        return FR_FAIL;
    
    pthread_rwlock_wrlock(&g_rwlock_mng);
    frlist_run(g_p_st_hdr_mng_module_del, NULL, __list_node_mng_chk_del);
    pthread_rwlock_unlock(&g_rwlock_mng);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  检查并删除不用模块
*  ARGS     :
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
FR_STATIC void *__frmodule_chk_module(void *arg)
{
    int i_loop =0;

    prctl(PR_SET_NAME,"check_module");
    while(g_i_flag_run)
    {
        __frmodule_del_no_ref();
        
        for(i_loop =0;g_i_flag_run && i_loop < APM_MNG_MODULE_CHK_TIME; i_loop++)
            sleep(1);
    }
    pthread_exit(0);
    
    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  按协议(tcp/udp),获取检查链表
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_data          (void *)
*  RTN      :
*  NOTE     : 0:pf_run控制退出; 1:运行到最后
*******************************************************************************/
FR_STATIC int __list_node_mng_mk_chklist(Frlist_node *p_st_node_in, const void *p_data)
{
    Frlist_node *p_st_node;
    Frchk_module_mng *p_st_chk_module=NULL;
    Frmodule_mng *p_st_module_mng=NULL;
    L7_module  *p_st_l7_module=NULL;
    
    if(p_st_node_in==NULL || p_st_node_in->data == NULL || p_data == NULL)
        return 1;

    p_st_chk_module = (Frchk_module_mng *)p_data;
    //获取节点下的管理模块
    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node_in);
    if(p_st_module_mng->i_is_stub == FR_YES )
        return 1;
    
    //比较 协议(tcp/udp)和端口
    p_st_l7_module = p_st_module_mng->p_st_l7_module;
    if( (p_st_l7_module->us_l4_proto & p_st_chk_module->i_ip_proto) == 0 )
        return 1;
    
    //协议自动判定
    if(p_st_module_mng->i_is_autocheck != p_st_chk_module->i_is_autocheck)
        return 1;

    //增加到查询链表
    p_st_node = frlist_node_create(p_st_module_mng);
    if(p_st_node == NULL)
        return 1;
    
    frlist_push(p_st_chk_module->p_lst_hdr, p_st_node);
    return 1;
}

/*******************************************************************************
*  FUNC     :  获取协议判断模块链表
*  ARGS     :  i_ip_proto      ( 6(IPPROTO_TCP)  / 17(IPPROTO_UDP) )
*           :  p_lst_hdr       ( 需要检查的协议保存在该链表 )
*           :  i_is_autocheck  (FR_YES:协议自动判定模块;FR_NO:协议不自动判定模块)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
int frmodule_get_chklist(int i_ip_proto, Frlist_header *p_lst_hdr, int i_is_autocheck)
{
    Frchk_module_mng st_chk_module;
    
    if(p_lst_hdr == NULL ) 
        return FR_FAIL;
    st_chk_module.p_lst_hdr = p_lst_hdr;
    st_chk_module.i_ip_proto = i_ip_proto;
    st_chk_module.i_is_autocheck = i_is_autocheck;
    
    pthread_rwlock_rdlock(&g_rwlock_mng);
    frlist_run(g_p_st_hdr_mng_module_use, &st_chk_module, __list_node_mng_mk_chklist);
    pthread_rwlock_unlock(&g_rwlock_mng);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  获取协议模块
*  ARGS     :  i_l7_proto      (全局使用的l7代号 )
*  RTN      :  Frmodule_mng*
*  NOTE     :  
*******************************************************************************/
FR_STATIC Frmodule_mng* __frmodule_get_module(int i_l7_proto)
{
    Frlist_node *p_st_node=NULL;
    Frmodule_mng *p_st_module_mng=NULL;
    L7_module st_l7_module;
    
    st_l7_module.i_l7_proto = i_l7_proto;
    
    p_st_node = frlist_find(g_p_st_hdr_mng_module_use, &st_l7_module, __list_node_mng_find_l7_proto);
    if(p_st_node == NULL || p_st_node->data == NULL)
        return NULL;
    
    p_st_module_mng = (Frmodule_mng*)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_module_mng->i_is_stub == FR_YES )
    {
        if(p_st_module_mng->p_st_l7_module)
            FRLOG_INFO_DETAIL("module [%s] is stub", p_st_module_mng->p_st_l7_module->p_module_name);
        return NULL;
    }
    
    return p_st_module_mng;
}

/*******************************************************************************
*  FUNC     :  获取协议模块
*  ARGS     :  i_l7_proto      (全局使用的l7代号 )
*  RTN      :  Frmodule_mng*
*  NOTE     :
*******************************************************************************/
Frmodule_mng *frmodule_get_module(int i_l7_proto)
{
    Frmodule_mng *p_st_module_mng=NULL;

    pthread_rwlock_rdlock(&g_rwlock_mng);
    p_st_module_mng = __frmodule_get_module(i_l7_proto);
    pthread_rwlock_unlock(&g_rwlock_mng);

    return p_st_module_mng;
}

/*******************************************************************************
*  FUNC     :  获取协议模块
*  ARGS     :  i_l7_proto      (全局使用的l7代号 )
*  RTN      :  L7_module*
*  NOTE     :  ul_refcnt++
*******************************************************************************/
L7_module *frmodule_get_l7module(int i_l7_proto)
{
    Frmodule_mng *p_st_module_mng=NULL;
    L7_module *p_st_l7_module=NULL;

    pthread_rwlock_rdlock(&g_rwlock_mng);
    p_st_module_mng = __frmodule_get_module(i_l7_proto);
    if(p_st_module_mng)
    {
        p_st_l7_module = p_st_module_mng->p_st_l7_module;
        __sync_fetch_and_add(&p_st_l7_module->ul_refcnt, 1);
    }
    pthread_rwlock_unlock(&g_rwlock_mng);

    return p_st_l7_module;
}

/*******************************************************************************
*  FUNC     :  减少协议模块引用
*  ARGS     :  p_st_l7_module      (L7_module * )
*  RTN      :
*  NOTE     :  ul_refcnt--
*******************************************************************************/
void frmodule_put_l7module(L7_module *p_st_l7_module)
{
    if(p_st_l7_module == NULL)
        return;

    __sync_fetch_and_sub(&p_st_l7_module->ul_refcnt, 1);
    return;
}

/*******************************************************************************
*  FUNC     :  管理模块内容出力
*  ARGS     :  p_st_hdr    (管理模块链表头指针)
*           :  p_title     (出力抬头)
*           :  pp_result   (出力结果)
*  RTN      : 
*  NOTE     :  1.注意如果传入pp_result,需要在外部释放内存
*           :  2.有长度限制
*******************************************************************************/
FR_STATIC void __frmodule_mng_output(Frlist_header *p_st_hdr, const char *p_title, char **pp_result)
{
    char *p_outbuff=NULL;
    int i_outbuff_size =1024000, i_used=0;

    if(p_st_hdr == NULL)
        return;

    p_outbuff = (char *) frmalloc(i_outbuff_size);
    if(p_outbuff==NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return;
    }

    snprintf(p_outbuff, i_outbuff_size, "regist module\n");
    i_used = strlen(p_outbuff);
    i_outbuff_size -= i_used;
    
    pthread_rwlock_rdlock(&g_rwlock_mng);
    frlist_show(p_st_hdr, p_outbuff+i_used, i_outbuff_size, frmodule_mng_list_node_mng_show);
    pthread_rwlock_unlock(&g_rwlock_mng);
    if(pp_result == NULL)
    {
        frdbg("==========================\n");
        printf("output %s data\n%s\n", p_title, p_outbuff);
        frdbg("==========================\n");
        frfree(p_outbuff);
    }
    else
        *pp_result = p_outbuff;

    return;
}

/*******************************************************************************
*  FUNC     :  管理模块内容出力
*  ARGS     :  pp_result   (出力结果)
*  RTN      : 
*  NOTE     :  1.注意如果传入pp_result,需要在外部释放内存
*           :  2.有长度限制
*******************************************************************************/
void frmodule_mng_output(char **pp_result)
{
    if(g_p_st_hdr_mng_module_use == NULL)
        return;
    
    __frmodule_mng_output(g_p_st_hdr_mng_module_use, "regist module", pp_result);

    return;
}

/*******************************************************************************
*  FUNC     :  模块管理初始化
*  ARGS     :
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frmodule_mng_init(void)
{
    int i_ret_fun;
    
    g_p_st_hdr_mng_module_use = frlist_create();
    if(g_p_st_hdr_mng_module_use == NULL)
        return FR_FAIL;

    g_p_st_hdr_mng_module_del = frlist_create();
    if(g_p_st_hdr_mng_module_del == NULL)
    {
        frfree(g_p_st_hdr_mng_module_use);
        return FR_FAIL;
    }

    i_ret_fun = pthread_create(&g_thread_id_chk, NULL, __frmodule_chk_module, NULL);
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("pthread_create err");
        g_thread_id_chk = 0L;
        frfree(g_p_st_hdr_mng_module_del);
        frfree(g_p_st_hdr_mng_module_use);
        return FR_FAIL;
    }

    return FR_SUCC;
}


/*******************************************************************************
*  FUNC     :  协议配置库内容转字符串，字段之间使用;分割
*  ARGS     :  p_lst_hdr                (Frlist_header*)
*           :  pp_outbuf                (出力字符串)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frmodule_cfg_params2str(Frlist_header *p_lst_hdr, const char *p_header, char **pp_outbuf)
{
    Frlist_node *p_st_node = NULL;
    Frvar_field *p_var_field = NULL;
    Frstr   *p_st_str=NULL;
    int i_first = FR_YES;

    if(p_lst_hdr == NULL || pp_outbuf==NULL)
        return;
    p_st_str = frstr_new(64);
    if(p_st_str == NULL)
        return;

    if(p_header && *p_header != '\0')
    {
        i_first = FR_NO;
        frstr_append(p_st_str, p_header, strlen(p_header)+1);
    }

    p_st_node = FRLIST_FIRST_NODE(p_lst_hdr);
    while(p_st_node)
    {
        p_var_field =  (Frvar_field*)FRLIST_GET_NODE_DATA(p_st_node);
        if(p_var_field == NULL || p_var_field->em_data_type != FRSTRING
          || p_var_field->field_value.p_value == NULL || *(p_var_field->field_value.p_value) == '\0')
        {
            p_st_node = FRLIST_NEXT_NODE(p_st_node);
            continue;
        }

        if(i_first == FR_YES)
        {
            frstr_append(p_st_str, p_var_field->field_value.p_value, strlen(p_var_field->field_value.p_value));
            i_first = FR_NO;
        }
        else
        {
            frstr_append(p_st_str, ";", 1);
            frstr_append(p_st_str, p_var_field->field_value.p_value, strlen(p_var_field->field_value.p_value));
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    *pp_outbuf = frstr_free2(&p_st_str);

    return;
}

/*******************************************************************************
*  FUNC     :  从配置文件中读取解析库配置
*  ARGS     :  p_module_file        (模块配置文件路径 const char*)
*  RTN      :  0:成功;1:失败;2:相同so已经加载;3:xml解析失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frmodule_load_one_module(const char *p_module_file)
{
    char *p_so_name=NULL, *p_so_name_full=NULL;
    const char*p_pos=NULL;
    char *p_l7_proto=NULL, *p_module_name=NULL, *p_module_params=NULL, *p_id=NULL, *p_tmp=NULL;
    int i_l7_proto=0, i_ret_fun=0, i_ret=1, i_len=0;
    Frlist_header *p_lst_hdr=NULL;
    xmlDocPtr p_st_doc=NULL;

    if(p_module_file == NULL || *p_module_file == '\0')
        return 1;

    p_st_doc = frxml_open_file(p_module_file);
    if(p_st_doc == NULL)
    {
        FRLOG_WARN_DETAIL("open file=[%s] fail", p_module_file);
        return 3;
    }

    //so路径
    i_ret_fun = frxml_get2ptr_string(p_st_doc, APM_CFG_MODULE_XPATH_MODULE, APM_CFG_MODULE_KEY_FILENAME, &p_so_name);
    if(i_ret_fun == FR_FAIL || p_so_name == NULL || *p_so_name == '\0')
    {
        FRLOG_WARN_DETAIL("load module err[%s] [%s] [%s]", p_module_file, APM_CFG_MODULE_XPATH_MODULE, APM_CFG_MODULE_KEY_FILENAME);
        goto END;
    }

    //获取p_so_name绝对路径
    p_pos = strrchr(p_module_file, '/');
    if(p_pos)
    {
        i_len = p_pos - p_module_file +1 ;
        p_so_name_full = (char *) frmalloc(i_len + strlen(p_so_name) + 1);
        if(p_so_name_full == NULL)
            goto END;
        memcpy(p_so_name_full, p_module_file, i_len);
        memcpy(p_so_name_full+i_len, p_so_name, strlen(p_so_name) + 1);
    }
    else
    {
        p_so_name_full = p_so_name;
        p_so_name = NULL;
    }
    //FRLOG_INFO_DETAIL("module xml=[%s] so=[%s]", p_module_file, p_so_name_full);

    //id
    i_ret_fun = frxml_get2ptr_prop_string(p_st_doc, "/", APM_CFG_MODULE_KEY_MODULE, APM_CFG_MODULE_KEY_ID, &p_id);
    if(p_id)
        frtrim(p_id);
    if(i_ret_fun == FR_FAIL || p_id == NULL || *p_id == '\0')
    {
        FRLOG_WARN_DETAIL("load module err[%s] [%s] [%s]", p_module_file, APM_CFG_MODULE_KEY_MODULE, APM_CFG_MODULE_KEY_ID);
        goto END;
    }

    //l7协议号
    i_ret_fun = frxml_get2ptr_prop_string(p_st_doc, "/", APM_CFG_MODULE_KEY_MODULE, APM_CFG_MODULE_KEY_L7_PROTO, &p_l7_proto);
    if(i_ret_fun == FR_FAIL || p_l7_proto == NULL || *p_l7_proto == '\0')
    {
        FRLOG_WARN_DETAIL("load module err[%s] [%s] [%s]", p_module_file, APM_CFG_MODULE_KEY_MODULE, APM_CFG_MODULE_KEY_L7_PROTO);
        goto END;
    }
    i_l7_proto = atoi(p_l7_proto);
    frfree(p_l7_proto);
    p_l7_proto = NULL;
    //协议名
    i_ret_fun = frxml_get2ptr_prop_string(p_st_doc, "/", APM_CFG_MODULE_KEY_MODULE, APM_CFG_MODULE_KEY_NAME, &p_module_name);
    if(i_ret_fun == FR_FAIL || p_module_name == NULL || *p_module_name == '\0')
    {
        FRLOG_WARN_DETAIL("load module err[%s] [%s] [%s]", p_module_file, APM_CFG_MODULE_KEY_MODULE, APM_CFG_MODULE_KEY_NAME);
        goto END;
    }
    //协议参数
    frxml_get_string_list(p_module_file, APM_CFG_MODULE_XPATH_ARGS, APM_CFG_MODULE_KEY_ARG, &p_lst_hdr);

    __frmodule_cfg_params2str(p_lst_hdr, "", &p_module_params);
    i_ret = __frmodule_register(p_module_file, p_so_name_full, i_l7_proto, p_module_name, p_module_params);
    FRLOG_INFO_DETAIL("load [%s] l7_proto=%d %s ret=%d(0:ok;1:fail;2:already load)", p_so_name_full, i_l7_proto, p_module_name, i_ret);

END:
    if(i_ret == FR_FAIL)
        FRLOG_WARN_DETAIL("load module[%s] err", p_module_file);
    if(p_tmp)
        frfree(p_tmp);
    if(p_lst_hdr)
        frxml_free_list(&p_lst_hdr);
    if(p_so_name)
        frfree(p_so_name);
    if(p_so_name_full)
        frfree(p_so_name_full);
    if(p_l7_proto)
        frfree(p_l7_proto);
    if(p_module_name)
        frfree(p_module_name);
    if(p_module_params)
        frfree(p_module_params);
    if(p_id)
        frfree(p_id);
    if(p_st_doc)
        frxml_close_file(p_st_doc);
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  卸载释放所有模块
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frmodule_unregister_all(void)
{
    /*
    pthread_rwlock_wrlock(&g_rwlock_mng);
    if(g_p_st_hdr_mng_module_del)
        frlist_remove_all(g_p_st_hdr_mng_module_del, __list_node_mng_free);
    if(g_p_st_hdr_mng_module_use)
        frlist_remove_all(g_p_st_hdr_mng_module_use, __list_node_mng_free);
    pthread_rwlock_unlock(&g_rwlock_mng);
    */

    Frmodule_mng *p_st_module_mng = NULL, *p_mng_module_del=NULL;
    Frlist_node *p_st_node_foreach=NULL, *p_st_node_new=NULL;
    L7_module *p_st_l7_module=NULL;

    pthread_rwlock_wrlock(&g_rwlock_mng);
    p_st_node_foreach = FRLIST_FIRST_NODE(g_p_st_hdr_mng_module_use);
    while(p_st_node_foreach)
    {
        p_st_module_mng = (Frmodule_mng*)FRLIST_GET_NODE_DATA(p_st_node_foreach);
        if(p_st_module_mng == NULL || p_st_module_mng->i_is_stub == FR_YES )
        {
            p_st_node_foreach = FRLIST_NEXT_NODE(p_st_node_foreach);
            continue;
        }

        //生成删除节点
        p_mng_module_del = (Frmodule_mng *) frmalloc(sizeof(Frmodule_mng));
        p_st_l7_module  = (L7_module *) frmalloc(sizeof(L7_module));
        if(p_mng_module_del == NULL || p_st_l7_module == NULL )
        {
            if(p_mng_module_del)
                frfree(p_mng_module_del);
            if(p_st_l7_module)
                frfree(p_st_l7_module);
            FRLOG_ERROR_DETAIL("frmalloc err");
            break;
        }

        memcpy(p_mng_module_del, p_st_module_mng, sizeof(Frmodule_mng));
        memset(p_st_l7_module, 0x00, sizeof(L7_module));
        p_st_module_mng->p_st_l7_module = p_st_l7_module;
        //stub里保留模块名
        if(p_mng_module_del->p_st_l7_module->p_module_name)
            p_st_module_mng->p_st_l7_module->p_module_name = frstrdup(p_mng_module_del->p_st_l7_module->p_module_name);
        //设置老节点为stub
        p_st_module_mng->i_is_stub = FR_YES;
        frl7module_stub(p_st_module_mng->p_st_l7_module);

        p_st_node_new = frlist_node_create(p_mng_module_del);
        if(p_st_node_new == NULL)
        {
            //该情况不应该发生，不考虑相关资源的释放
            //if(p_mng_module_del->p_st_l7_module && p_mng_module_del->p_st_l7_module->p_module_name)
            //    frfree(p_mng_module_del->p_st_l7_module->p_module_name);
            //if(p_mng_module_del->p_st_l7_module)
            //    frfree(p_mng_module_del->p_st_l7_module);
            frfree(p_mng_module_del);
            FRLOG_ERROR_DETAIL("frmalloc err");
            break;
        }
        p_st_module_mng->p_st_l7_module->l_del_tv_sec = 0;
        frlist_push(g_p_st_hdr_mng_module_del, p_st_node_new);

        p_st_node_foreach = FRLIST_NEXT_NODE(p_st_node_foreach);
    }

    pthread_rwlock_unlock(&g_rwlock_mng);
    return;
}

/*******************************************************************************
*  FUNC     :  模块管理资源释放
*  ARGS     :  
*  RTN      :  
*  NOTE     :
*******************************************************************************/
void frmodule_mng_destory(void)
{
    if(g_thread_id_chk)
        pthread_join(g_thread_id_chk, NULL);

    if(g_p_st_hdr_mng_module_del)
    {
        frlist_destroy(g_p_st_hdr_mng_module_del, __list_node_mng_free);
        g_p_st_hdr_mng_module_del = NULL;
    }

    if(g_p_st_hdr_mng_module_use)
    {
        frlist_destroy(g_p_st_hdr_mng_module_use, __list_node_mng_free);
        g_p_st_hdr_mng_module_use = NULL;
    }

    return;
}
